import 'package:flutter/material.dart';

class ModelBindingV1 extends StatefulWidget {
  ModelBindingV1(
      {Key? key, this.initialModel = const ViewModel(), required this.child})
      : super(key: key);
  final ViewModel initialModel;
  final Widget child;

  @override
  _ModelBindingV1State createState() => _ModelBindingV1State();
}

class _ModelBindingV1State extends State<ModelBindingV1> {
  ViewModel currentModel = ViewModel();

  void updateModel(ViewModel newModel) {
    if (currentModel != newModel) {
      setState(() {
        currentModel = newModel;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return _ModelBindingScope(
      modelBindingState: this,
      child: widget.child,
    );
  }
}

class ViewModel {
  final int value;
  const ViewModel({this.value = 0});

  @override
  bool operator ==(Object other) {
    if (identical(this, other)) return true;
    if (other.runtimeType != runtimeType) {
      return false;
    }
    // ignore: test_types_in_equals
    final ViewModel otherModel = other as ViewModel;
    return otherModel.value == value;
  }

  @override
  int get hashCode => value.hashCode;

  static ViewModel of(BuildContext context) {
    _ModelBindingScope? scope =
        context.dependOnInheritedWidgetOfExactType(aspect: _ModelBindingScope);
    return scope!.modelBindingState.currentModel;
  }

  static void update(BuildContext context, ViewModel newModel) {
    _ModelBindingScope? scope =
        context.dependOnInheritedWidgetOfExactType(aspect: _ModelBindingScope);
    scope!.modelBindingState.updateModel(newModel);
  }
}

class _ModelBindingScope extends InheritedWidget {
  _ModelBindingScope({
    Key? key,
    required this.modelBindingState,
    required Widget child,
  }) : super(key: key, child: child);

  final _ModelBindingV1State modelBindingState;

  @override
  bool updateShouldNotify(_ModelBindingScope oldWidget) => true;
}
